﻿/* 
 * Copyright (c) 2009, Jason D. Montgomery
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright notice, this 
 *   list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright notice, 
 *   this list of conditions and the following disclaimer in the documentation 
 *   and/or other materials provided with the distribution.
 * 
 * * Neither the name of ATGi nor the names of its contributors may be used to 
 *   endorse or promote products derived from this software without specific 
 *   prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 * THE POSSIBILITY OF SUCH DAMAGE.
 */
using System;
using System.Collections.Generic;
using System.Text;
using Fiddler;
using Fiddler.WebTesting;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace DnSecAnalysis
{
    public class DnSecAnalysisPlugIn : IFiddlerExtension
    {
        private TabPage oPage;
        private ViewStateDecoderControl oViewStateDecoderTab;
        private static Regex _viewStateregex = new Regex(
            "<input type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE" +
            "\" value=\"([a-zA-Z0-9+=/]+)\" />",
            RegexOptions.CultureInvariant | RegexOptions.Compiled
        );

        #region IFiddlerExtension Members

        public void OnBeforeUnload()
        {
        }

        public void OnLoad()
        {
            this.oPage = new TabPage("ViewState Decoder");
            this.oViewStateDecoderTab = new ViewStateDecoderControl();
            this.oPage.Controls.Add(this.oViewStateDecoderTab);
            this.oViewStateDecoderTab.Dock = DockStyle.Fill;
            FiddlerApplication.UI.tabsViews.SelectedIndexChanged += new EventHandler(tabsViews_SelectedIndexChanged);
            
            SessionListView lvSessions = (SessionListView)FiddlerApplication.UI.pnlSessions.Controls["lvSessions"];
            lvSessions.SelectedIndexChanged += new EventHandler(lvSessions_SelectedIndexChanged);
            
            // TODO Setup Image/Icon
            // FiddlerApplication.UI.imglSessionIcons.Images.Add("ViewStateDecoder", Resources.viewStateIcon);
            // this.oPage.ImageIndex = FiddlerApplication.UI.imglSessionIcons.Images.IndexOfKey("ViewStateDecoder");

            FiddlerApplication.UI.tabsViews.TabPages.Add(this.oPage);
        }

        void lvSessions_SelectedIndexChanged(object sender, EventArgs e)
        {
            FindSessionAndDecodeViewState();
        }

        void tabsViews_SelectedIndexChanged(object sender, EventArgs e)
        {
            FindSessionAndDecodeViewState();
        }

        private void FindSessionAndDecodeViewState()
        {
            oViewStateDecoderTab.ClearText();
            if (FiddlerApplication.UI.tabsViews.SelectedTab == this.oPage)
            {
                foreach (Session oSession in FiddlerApplication.UI.GetSelectedSessions())
                {
                    if (oSession.bHasResponse && oSession.responseBodyBytes != null)
                    {
                        MemoryStream ms = new MemoryStream(oSession.responseBodyBytes);
                        StreamReader sr = new StreamReader(ms);

                        oViewStateDecoderTab.Write("Inspecting " + oSession.url + " for ViewState." + Environment.NewLine);
                        while (sr.Peek() >= 0)
                        {
                            string currentLine = sr.ReadLine();
                            if (currentLine.Contains("__VIEWSTATE"))
                            {
                                Match viewStateMatch = _viewStateregex.Match(currentLine);
                                if (viewStateMatch.Success)
                                {
                                    string viewState = viewStateMatch.Groups[1].Value;
                                    oViewStateDecoderTab.ParseViewState(viewState);
                                }
                            }
                        }
                        oViewStateDecoderTab.Write(Environment.NewLine);
                    }
                    else
                    {
                        oViewStateDecoderTab.Write("No VIEWSTATE found.");
                    }
                }
            }
        }
        #endregion
    }
}
